﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Taxonomy;

namespace MMMigrator.ClassLibrary
{
    /// <summary>
    /// Utility class for generating Managed Metadata Service configuration in XML format
    /// Mac McEldon March 2011
    /// </summary>
    public static class ExportMetadata
    {
        #region Main Methods

        /// <summary>
        /// Main Method to instantiate SP objects and fire the XML generation
        /// </summary>
        /// <param name="strSiteName">Site Collection URL</param>
        /// <param name="strGroupName">The target group in the Default Site Collection Terms Store</param>
        /// <returns>XML</returns>
        public static XElement GenerateExportXML(string strSiteName, string strGroupName)
        {
            XElement xmlRoot = null;

            // Set SP objects using dispose method
            using (SPSite objSite = new SPSite(strSiteName))
            {
                using (SPWeb objWeb = objSite.OpenWeb())
                {
                    // Instantiate SP Taxonomy Objects
                    // Ensure the target term store has the correct settings applied (DefaultSiteCollectionTermStore)
                    TaxonomySession objSession = new TaxonomySession(objSite);
                    TermStore objTermStore = objSession.DefaultSiteCollectionTermStore;
                    Group objGroup = objTermStore.Groups[strGroupName];

                    // Set Document root
                    xmlRoot = new XElement("TermSets");

                    // Iterate Term Set
                    foreach (TermSet objTermSet in objGroup.TermSets)
                    {
                        XElement currentTermSet = GetTermSet(objTermSet);
                        xmlRoot.Add(currentTermSet);
                    }
                }
            }

            return xmlRoot;
        }

        #endregion

        #region Utility Methods

        /// <summary>
        /// Iterates and returns a term set
        /// </summary>
        /// <param name="objTermSet">TermSet</param>
        /// <returns>XElement</returns>
        private static XElement GetTermSet(TermSet objTermSet)
        {
            // Create Termset node and add attributes
            XElement xmlTermsSetNode = new XElement("TermSet",
                new XAttribute("Name", objTermSet.Name),
                new XAttribute("Description", objTermSet.Description),
                new XAttribute("Contact", objTermSet.Contact),
                new XAttribute("Owner", objTermSet.Owner),
                new XAttribute("ID", objTermSet.Id.ToString()),
                new XAttribute("IsOpenForTermCreation", objTermSet.IsOpenForTermCreation.ToString()),
                new XAttribute("IsAvailableForTagging", objTermSet.IsAvailableForTagging.ToString()));

            // Check for stakeholders and add nodes if present
            // Note that the stakeholders come back with some strange chars at the beginning of the string;
            // See http://social.technet.microsoft.com/Forums/en-US/sharepoint2010setup/thread/c96892ea-36df-446e-8731-03e01e8913b9
            if (objTermSet.Stakeholders.Count != 0)
            {
                xmlTermsSetNode.Add(new XElement("Stakeholders"));
                foreach (string strStakeHolder in objTermSet.Stakeholders)
                {
                    xmlTermsSetNode.Element("Stakeholders").Add(new XElement("Stakeholder", strStakeHolder));
                }
            }

            // Check for terms and add nodes if present
            if (objTermSet.Terms.Count != 0)
            {
                xmlTermsSetNode.Add(GetTerms(objTermSet.Terms));
            }

            return xmlTermsSetNode;
        }

        /// <summary>
        /// Iterates and returns a Term
        /// Note that a term can have children also.
        /// </summary>
        /// <param name="objTermCollection">TermCollection</param>
        /// <returns>XElement</returns>
        private static XElement GetTerms(TermCollection objTermCollection)
        {
            XElement xmlTermsNode = new XElement("Terms");

            // Create term node and add attributes
            foreach (Term objTerm in objTermCollection)
            {
                XElement xmlTermNode = new XElement("Term",
                    new XAttribute("Description", objTerm.GetDescription()),
                    new XAttribute("IsAvailableForTagging", objTerm.IsAvailableForTagging.ToString()),
                    new XAttribute("Name", objTerm.Name),
                    GetLabels(objTerm)
                    );

                // Check for exisitnce of child terms and add nodes accordingly
                if (objTerm.Terms.Count != 0)
                {
                    xmlTermNode.Add(GetTerms(objTerm.Terms));
                }

                xmlTermsNode.Add(xmlTermNode);
            }

            return xmlTermsNode;
        }

        /// <summary>
        /// Iterates and returns term labels
        /// </summary>
        /// <param name="objTerm">Term</param>
        /// <returns>XElement</returns>
        private static XElement GetLabels(Term objTerm)
        {
            XElement xmlLabelNode = new XElement("Labels");

            // Create Label node and add attributes.
            foreach (Label objLabel in objTerm.Labels)
            {
                xmlLabelNode.Add(new XElement("Label",
                    new XAttribute("IsDefault", objLabel.IsDefaultForLanguage.ToString()),
                    new XAttribute("Language", objLabel.Language),
                    objLabel.Value));
            }

            return xmlLabelNode;
        }

        #endregion
    }
}
